#include "STable.h"
#include <QTableView>
#include <QHeaderView>
#include <QScrollBar>
#include <QPainter>
#include <QHBoxLayout>
#include <QFile>
#include <QWheelEvent>
#include <core/StyleMgr.h>

static const int FLASH_NUMBER = 15; //200ms * 15

DefaulTableItemDelegate::DefaulTableItemDelegate(QObject* p)
	: QStyledItemDelegate(p)
{

}

void DefaulTableItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	painter->setPen(StyleMgr::instance().color("BasicPlate"));
	painter->drawRect(option.rect);
	QStyleOptionViewItem itemOption(option);
	//去掉选中时的虚线框
	if (itemOption.state & QStyle::State_HasFocus)
		itemOption.state = itemOption.state ^ QStyle::State_HasFocus;

	itemOption.palette.setColor(QPalette::Highlight, StyleMgr::instance().color("Hover"));
	//选中字体颜色不变
	itemOption.palette.setColor(QPalette::HighlightedText, index.data(Qt::ForegroundRole).value<QColor> ());

	//图片位置修正
	if ((index.data(Qt::TextAlignmentRole).toInt() & Qt::AlignRight) == Qt::AlignRight)
		itemOption.decorationPosition = QStyleOptionViewItem::Right;

	QPixmap prefixImg = index.data(PrefixImgRole).value<QPixmap>();
	QPixmap postfixImg = index.data(PostfixImgRole).value<QPixmap>();
	if (!prefixImg.isNull() || !postfixImg.isNull())
	{
		painter->save();
		initStyleOption(&itemOption, index);
		painter->fillRect(itemOption.rect, (itemOption.state & QStyle::State_Selected) ? itemOption.palette.color(QPalette::Highlight) : itemOption.backgroundBrush);

		QRect r = itemOption.rect;
		r.setRight(r.right() - 4);
		if (!postfixImg.isNull())
		{
			painter->drawPixmap(r.right() - postfixImg.width() / postfixImg.devicePixelRatioF(), r.bottom() - postfixImg.height() / postfixImg.devicePixelRatioF() - 4, postfixImg);//TODO DPI
			r.setRight(r.right() - postfixImg.width() / postfixImg.devicePixelRatioF() - 2);
		}

		QString txt = index.data(Qt::DisplayRole).toString();
		painter->setPen(index.data(Qt::ForegroundRole).value<QColor>());
		painter->setFont(index.data(Qt::FontRole).value<QFont>());
		painter->drawText(r, txt, QTextOption(Qt::AlignRight | Qt::AlignVCenter));

		if (!prefixImg.isNull())
		{
			QFontMetrics fm(painter->font());
			int w = fm.horizontalAdvance(txt);
			r.setRight(r.right() - w - 2);

			painter->drawPixmap(r.right() - prefixImg.width() / postfixImg.devicePixelRatioF(), r.center().y() - prefixImg.height() / postfixImg.devicePixelRatioF() / 2, prefixImg);
		}
		painter->restore();
	}
	else
		QStyledItemDelegate::paint(painter, itemOption, index);

	painter->setPen(StyleMgr::instance().color("PartPlate"));
	painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
}

SVirtualTable::SVirtualTable(QWidget* p)
	: QWidget(p)
{
	QHBoxLayout* l = new QHBoxLayout(this);
	l->setContentsMargins(0, 0, 0, 0);
	l->setSpacing(0);
	setLayout(l);

	m_table = new QTableView(this);
	m_table->setAutoScroll(false);
	m_table->installEventFilter(this);
	m_table->setStyleSheet(QString("QTableView{background-color:#%1;border:0px solid white;}")
		.arg(StyleMgr::instance().color("BasicPlate").rgb(), 0, 16));

	QFont headerFont = font();
	headerFont.setBold(true);
	m_table->horizontalHeader()->setFont(headerFont);
	m_table->horizontalHeader()->setHighlightSections(false);
	m_table->horizontalHeader()->setStyleSheet(QString("QHeaderView::section {"
		"background-color: #%1;color:#%2; padding-left: 4px;padding-right: 4px;height:24px;border:none;border-right:1px solid #%3}")
		.arg(StyleMgr::instance().color("PartPlate").rgb(), 0, 16)
		.arg(StyleMgr::instance().color("TitleWord").rgb(), 0, 16)
		.arg(StyleMgr::instance().color("BasicPlate").rgb(), 0, 16));
	m_table->setShowGrid(false);
	m_table->verticalHeader()->hide();    //隐藏默认显示的行头
	m_table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	m_table->setSelectionBehavior(QAbstractItemView::SelectRows); //设置选中时整行选中
	m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);  //设置表格属性只读，不能编辑
	m_table->verticalHeader()->setDefaultSectionSize(24);//TODO sectionSize的设置原理
	m_table->setItemDelegate(new DefaulTableItemDelegate(this));
	l->addWidget(m_table);

	m_scrollBar = new QScrollBar(this);
	m_scrollBar->hide();
	m_scrollBar->setValue(0);
	m_scrollBar->setFixedWidth(8);
	l->addWidget(m_scrollBar);

	connect(m_scrollBar, &QScrollBar::valueChanged, this, &SVirtualTable::viewPosChanged);
	m_flashTimer = new QTimer();
	m_flashTimer->callOnTimeout(this, &SVirtualTable::onTimeOut);
}

void SVirtualTable::setRealDataCount(int c)
{
	if (m_realDataCount != c)
	{
		m_realDataCount = c;
		resetScroll();
	}
}

int SVirtualTable::sliderPos() const
{
	return m_scrollBar->value();
}

void SVirtualTable::resetScroll(bool resetPos /*= false*/)
{
	if (m_pageCount < m_realDataCount)
		m_scrollBar->show();
	else
		m_scrollBar->hide();

	if (resetPos ||  m_scrollBar->value() > m_realDataCount)
		m_scrollBar->setValue(0);

	m_scrollBar->setRange(0, m_realDataCount - m_pageCount);
	m_scrollBar->setPageStep(m_pageCount);
	m_scrollBar->setSingleStep(1);
}

bool SVirtualTable::isVScrollBarShown()
{
	return m_pageCount < m_realDataCount;
}

bool SVirtualTable::eventFilter(QObject* watched, QEvent* event)
{
	if (watched == m_table && event->type() == QEvent::Type::Wheel && m_realDataCount > m_pageCount)
	{
		QWheelEvent* we = static_cast<QWheelEvent*>(event);

		int delta = we->angleDelta().y();
		int pos = m_scrollBar->value();
		int step = m_scrollBar->singleStep();
		int nMax = m_scrollBar->maximum();

		if (delta > 0)
		{
			pos -= step;
			pos = qMax(0, pos);
		}
		else
		{
			pos += step;
			pos = std::min(pos, nMax);
		}

		m_scrollBar->setValue(pos);
	}
	else if (watched == m_lockIndicator && event->type() == QEvent::MouseButtonPress)
	{
		QMouseEvent* me = dynamic_cast<QMouseEvent*>(event);
		if (me->buttons().testFlag(Qt::LeftButton))
		{
			unlockTable();
			emit unlocked();
		}
	}

	return QWidget::eventFilter(watched, event);
}

void SVirtualTable::resizeEvent(QResizeEvent* event)
{
	const int ROW_HIGHT = m_table->verticalHeader()->defaultSectionSize();
	int pageCount = rect().height() / ROW_HIGHT;
	if (pageCount != m_pageCount)
	{
		m_pageCount = pageCount;
		resetScroll();

		DefaultTableModel* myModel = dynamic_cast<DefaultTableModel*>(m_table->model());
		if (myModel)
			myModel->setRowCount(m_pageCount);
	}

	emit viewPosChanged(m_scrollBar->value());

	updateLockGeo();
}

void SVirtualTable::onTimeOut()
{
	DefaultTableModel* myModel = dynamic_cast<DefaultTableModel*>(m_table->model());
	if (!myModel)
		return;

	if (!myModel->flash())
		m_flashTimer->stop();
}


void SVirtualTable::addFlashInfo(const FlashInfo& fi, bool startImmediately)
{
	DefaultTableModel* myModel = dynamic_cast<DefaultTableModel *>(m_table->model());
	if (!myModel)
		return;

	myModel->addFlashInfo(fi);
	if (startImmediately)
	{
		myModel->flash();
		m_flashTimer->start(200);
	}
}

void SVirtualTable::removeFlashInfo(const FlashInfo& fi)
{
	DefaultTableModel* myModel = dynamic_cast<DefaultTableModel*>(m_table->model());
	if (!myModel)
		return;

	myModel->removeFlashInfo(fi);
}

void SVirtualTable::startFlash()
{
	DefaultTableModel* myModel = dynamic_cast<DefaultTableModel*>(m_table->model());
	if (!myModel)
		return;

	if(myModel->flash())
		m_flashTimer->start(200);
}

void SVirtualTable::setHeaderSortable(bool v)
{
	m_headerSortable = v;
	if (m_headerSortable)
	{
		m_table->horizontalHeader()->setSectionsClickable(true);
		connect(m_table->horizontalHeader(), &QHeaderView::sectionPressed, this, &SVirtualTable::onHeaderClicked);
	}
}

void SVirtualTable::lockTable()
{
	if (!m_lockIndicator)
	{
		m_lockIndicator = new QLabel(this);
		QColor clr = StyleMgr::instance().color("Orange04");
		clr.setAlpha(0x80);
		m_lockIndicator->setStyleSheet(QString("background-color:#%1").arg(clr.rgba(), 0, 16));
		m_lockIndicator->setAlignment(Qt::AlignCenter);
		m_lockIndicator->installEventFilter(this);
	}
	m_locked = true;
	m_lockIndicator->raise();
	updateLockGeo();
	m_lockIndicator->show();
}

void SVirtualTable::unlockTable()
{
	if (m_locked && m_lockIndicator)
	{
		m_lockIndicator->hide();
		m_lockIndicator->setText("");
	}
}

void SVirtualTable::showLockNewData(const QString& tip)
{
	if (m_lockIndicator)
		m_lockIndicator->setText(tip);
}

void SVirtualTable::clearTable()
{
	DefaultTableModel* myModel = dynamic_cast<DefaultTableModel*>(m_table->model());
	if (!myModel)
		return;

	int colCount = myModel->columnCount();
	for (int i = 0; i < m_pageCount; ++i)
	{
		for (int col = 0; col < colCount; ++col)
		{
			QStandardItem* item = myModel->item(i, col);
			if (item == nullptr)
			{
				item = new QStandardItem();
				myModel->setItem(i, col, item);
			}
			else
				item->clearData();
		}
	}
}

void SVirtualTable::onHeaderClicked(int logicalIndex)
{
	emit headerSort(logicalIndex);
}

void SVirtualTable::updateLockGeo()
{
	if (!m_locked || !m_lockIndicator)
		return;
	m_lockIndicator->setGeometry(0, 0, rect().width(), 24);
}

DefaultTableModel::DefaultTableModel(QObject* p)
	: QStandardItemModel(p)
{

}

QVariant DefaultTableModel::data(const QModelIndex& index, int role /*= Qt::DisplayRole*/) const
{
	if (role == Qt::ToolTipRole)
	{
		QString tooltip = QStandardItemModel::data(index, role).toString();
		if (!tooltip.isEmpty())
			return tooltip;

		QString txt = index.data(Qt::DisplayRole).toString();
		QFontMetrics fm(index.data(Qt::FontRole).value<QFont>());
		int txtWidth = fm.horizontalAdvance(txt);
		if (txtWidth > m_table->table()->horizontalHeader()->sectionSize(index.column()))
		{
			return txt;
		}

		QPixmap prefixImg = index.data(PrefixImgRole).value<QPixmap>();
		QPixmap postfixImg = index.data(PostfixImgRole).value<QPixmap>();
		if (!prefixImg.isNull() || !postfixImg.isNull())
		{
			QRect rect = m_table->table()->visualRect(index);
			if (m_table->table()->horizontalHeader()->isVisible())
				rect.moveTop(rect.top() + m_table->table()->horizontalHeader()->height());

			QPoint cusorPos = QCursor::pos();
			cusorPos = m_table->table()->mapFromGlobal(cusorPos);

			QRect r = rect;
			if (!postfixImg.isNull())
			{
				r.setRight(r.right() - 4);
				r.setLeft(r.right() - postfixImg.width());
				r.setTop(r.bottom() - 4 - postfixImg.height());
				r.setHeight(postfixImg.height());

				if (r.contains(cusorPos))
					return index.data(PostfixTipRole).toString();
				else
					r.setRight(r.left() - 2);
			}

			if (!prefixImg.isNull())
			{
				r.setRight(r.right() - txtWidth - 2);
				r.setLeft(r.right() - prefixImg.width());
				r.setTop(r.center().y() - prefixImg.height() / 2);
				r.setHeight(prefixImg.height());

				if (r.contains(cusorPos))
					return index.data(PrefixTipRole).toString();
			}
		}
	}
	else if (role == Qt::BackgroundRole)
	{
		QString id = index.data(DataIdRole).toString();
		auto iter = m_flashInfos.find(id);
		if (iter != m_flashInfos.end())
		{
			if(!iter->second.entireRow && 
				std::find(iter->second.cols.begin(), iter->second.cols.end(), index.column()) == iter->second.cols.end())
				return QStandardItemModel::data(index, role);

			QColor bkClr = StyleMgr::instance().color("NewData");
			float alpha = float(FLASH_NUMBER - iter->second.flashCount) / FLASH_NUMBER;
			bkClr.setAlphaF(alpha < 0 ? 1 : alpha);
			return bkClr;
		}
	}

	return QStandardItemModel::data(index, role);
}

void DefaultTableModel::addFlashInfo(const FlashInfo& fi)
{
	m_flashInfos[fi.id] = fi;
}

void DefaultTableModel::removeFlashInfo(const FlashInfo& fi)
{
	m_flashInfos.erase(fi.id);
}

bool DefaultTableModel::flash()
{
	for (auto iter = m_flashInfos.begin(); iter != m_flashInfos.end();)
	{
		if ((++iter->second.flashCount) > FLASH_NUMBER)
			iter = m_flashInfos.erase(iter);
		else
			++iter;
	}
	if (!m_flashInfos.empty() && m_table)
		m_table->update();

	return !m_flashInfos.empty();
}